﻿#define TTS
#define EMAIL1

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using FX.CC.Andon.BroadcastService.BroadcastSvcRef;
using System.Configuration;
#if TTS
using System.Speech.Synthesis;
#endif

namespace FX.CC.Andon.BroadcastService
{
    public partial class BroadcastSvc : ServiceBase
    {
        const string log_source = "Broadcast Service Log";
#if TTS
        const string replacement_key_str = "Replacement";
        const string speaker_key_str = "Speaker";
        const char pair_sp_char = ';';
        const char k_v_sp_char = '|';
#endif

#if EMAIL
        #region About SMTP CONST
        const string smtp_server_cfg_key = "SMTPServer";
        const string smtp_port_cfg_key = "SMTPPort";
        const string smtp_ssl_cfg_key = "SMTPSSL";
        const string smtp_rv_max_count_key = "MaxRVCount";
        const string email_addr_cfg_key = "EmailAddr";
        const string email_pwd_cfg_key = "EmailPwd";

        const string svc_use_proxy_cfg_key = "UseProxy";
        const string svc_proxy_host_cfg_key = "ProxyHost";
        const string svc_proxy_port_cfg_key = "ProxyPort";
        #endregion
#endif

#if TTS
        readonly Uri alarmSndUri;
#endif

        DateTime lastGetTime;

        Thread eventTh;
        BroadcastDataSvc svc;
#if TTS
        SpeechSynthesizer svInstance;
        IList<KeyValuePair<string, string>> replaceList;
        string speaker;
#endif

#if EMAIL
        /// <summary>
        /// 邮件发送客户端
        /// </summary>
        MailService.ExcProxy mailSvc;
        MailService.MConfig mCfg;
#endif

        public BroadcastSvc()
        {
            InitializeComponent();

            if (!EventLog.SourceExists(log_source))
                EventLog.CreateEventSource(log_source, "Ty Broadcast Service Log");

#if TTS
            string sndFileName = System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName) + "\\Alarm.WAV";
            this.alarmSndUri = new Uri(sndFileName);
#endif
        }

        protected override void OnStart(string[] args)
        {
#if DEBUG
            EventLog.WriteEntry(log_source, "广播服务调试版本!", EventLogEntryType.Warning);
#endif

#if TTS
            speaker = ConfigurationManager.AppSettings[speaker_key_str];
            replaceList = new List<KeyValuePair<string, string>>();
            //read config
            string rpStr = ConfigurationManager.AppSettings[replacement_key_str];
            var pairStrArr = rpStr.Split(pair_sp_char);
            foreach (var pairStr in pairStrArr)
            {
                var pair = pairStr.Split(k_v_sp_char);
                replaceList.Add(new KeyValuePair<string, string>(pair[0], pair[1]));
            }
#endif

            //init broadcast service
            svc = new BroadcastDataSvc();

            //init tts
#if TTS
            svInstance = new SpeechSynthesizer();
            svInstance.SelectVoice(speaker);

            EventLog.WriteEntry(log_source, "广播服务已启动!", EventLogEntryType.Information);
            svInstance.Speak("欢迎使用安灯广播系统!");
#endif

#if EMAIL
            mCfg = new MailService.MConfig();
            //init smtp
            mCfg.MHost = ConfigurationManager.AppSettings[smtp_server_cfg_key].Trim();
            string smtpPortStr = ConfigurationManager.AppSettings[smtp_port_cfg_key].Trim();
            int smtpPort = 25;
            int.TryParse(smtpPortStr, out smtpPort);
            mCfg.MPort = smtpPort;
            mCfg.SSL = ConfigurationManager.AppSettings[smtp_ssl_cfg_key].Trim() == "1";
            mCfg.MFrom = ConfigurationManager.AppSettings[email_addr_cfg_key].Trim();
            mCfg.FName = "Andon Messager";
            mCfg.AccName = mCfg.MFrom;
            mCfg.AccPwd = ConfigurationManager.AppSettings[email_pwd_cfg_key].Trim();
            string str = mCfg.MFrom + mCfg.FName + mCfg.MHost + mCfg.AccPwd;
            mCfg.Verification = GetMD5Hash(str);
            mCfg.MSubject = "Andon系统异常信息自动推送邮件";
            int maxRvCount = 40;//默认设置为40
            string maxRvCountStr = ConfigurationManager.AppSettings[smtp_rv_max_count_key];
            int.TryParse(maxRvCountStr, out maxRvCount);
            mCfg.MaxRVCount = maxRvCount;

            //mail webservice
            mailSvc = new MailService.ExcProxy();
            bool useSvcProxy = ConfigurationManager.AppSettings[svc_use_proxy_cfg_key] == "1";
            if (useSvcProxy)
            {
                string proxyHost = ConfigurationManager.AppSettings[svc_proxy_host_cfg_key];
                string proxyPortStr = ConfigurationManager.AppSettings[svc_proxy_port_cfg_key];
                int proxyPort = 8080;
                int.TryParse(proxyPortStr, out proxyPort);
                System.Net.WebProxy oWebProxy = new System.Net.WebProxy(proxyHost, proxyPort);
                mailSvc.Proxy = oWebProxy;
                EventLog.WriteEntry(log_source, "启用代理，" + proxyHost + ":" + proxyPortStr, EventLogEntryType.Warning);
            }
            
#endif

            //init thread
            eventTh = new Thread(DoGetEventRec);
            eventTh.IsBackground = true;
            eventTh.Start();
            lastGetTime = DateTime.Now;
        }

        
#if EMAIL
        static string GetMD5Hash(string input)
        {
            System.Security.Cryptography.MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] bs = System.Text.Encoding.UTF8.GetBytes(input);
            bs = x.ComputeHash(bs);
            System.Text.StringBuilder s = new System.Text.StringBuilder();
            foreach (byte b in bs)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string password = s.ToString();
            return password;
        }
#endif

        protected override void OnStop()
        {
            EventLog.WriteEntry(log_source, "广播服务已停止!", EventLogEntryType.Warning);
            try
            {
                svc.Dispose();
                eventTh.Abort();
            }
            catch { }
        }


        void DoGetEventRec()
        {
            Thread.Sleep(30000);
            while (true)
            {
                Thread.Sleep(5000);
                try
                {
                    var wrapper = svc.GetEventRec(this.lastGetTime);
                    this.lastGetTime = wrapper.GetTime;


                    foreach (var errRec in wrapper.RecArr)
                    {
#if EMAIL
                        var context = new SendMainContext();
                        context.ETypeCode = errRec.ETypeCode;
                        string content =
@"Dear All，
    以下是异常信息：
    产线：{0}
    设备：{1}
    异常类别：{2}
    异常明细：{3}
    触发人员：{4}
    触发时间：{5}
无需回复此邮件，谢谢！
Best Regards!";
                        content = string.Format(content, errRec.LineName, errRec.EqName, errRec.ETypeName,
                            errRec.DetailName, errRec.FullName, errRec.StartTime);
                        context.Content = content;
                        //发邮件，放入线程池
                        ThreadPool.QueueUserWorkItem(SendMail, context);
#endif

#if TTS
                        //"支援部门请注意，{0}的{1}设备发生{2}，请相关人员了解详情后速到事发现场进行签到处理！感谢你的配合！
                        foreach (var rp in replaceList)
                        {
                            errRec.LineName = errRec.LineName.Replace(rp.Key, rp.Value);
                            errRec.EqName = errRec.EqName.Replace(rp.Key, rp.Value);
                        }

                        Broadcast(errRec);
                        Thread.Sleep(5000);
                        Broadcast(errRec);
#endif
                    }
#if TTS
                    if (wrapper.RecArr.Length > 0)
                    {
                        EventLog.WriteEntry(log_source, "广播系统播报了" + wrapper.RecArr.Length.ToString() + "条异常！", EventLogEntryType.Information);
                    }
#endif
                }
                catch (Exception ex)
                {
                    EventLog.WriteEntry(log_source, ex.ToString(), EventLogEntryType.Error);
                }
            }
        }

 #if TTS
        void Broadcast(EventRecWrapper obj)
        {
            PromptBuilder ctrlPrompt = new PromptBuilder();
            //Start the main speaking style
            PromptStyle ctrlStyle = new PromptStyle();
            ctrlStyle.Rate = PromptRate.Medium;
            ctrlStyle.Volume = PromptVolume.ExtraLoud;
            ctrlStyle.Emphasis = PromptEmphasis.Strong;
            ctrlPrompt.StartStyle(ctrlStyle);
            //Alert the listener
            ctrlPrompt.AppendAudio(this.alarmSndUri);
            ctrlPrompt.AppendText("支援部门请注意,以下是异常播报:");
            ctrlPrompt.AppendBreak();

            string mainBody = "{0}生产线的设备:{1}发生{2}";
            mainBody = string.Format(mainBody, obj.LineName, obj.EqName, obj.ETypeName);
            ctrlPrompt.AppendText(mainBody);
            ctrlPrompt.AppendBreak();
            ctrlPrompt.AppendText("具体原因：" + obj.DetailName);
            ctrlPrompt.AppendBreak();
            ctrlPrompt.AppendText("播报完毕！");
            ctrlPrompt.EndStyle();

            //Now let's get the synthesizer to render this message
            svInstance.Speak(ctrlPrompt);
        }
#endif

#if EMAIL
        void SendMail(object obj)
        {
            var context = (SendMainContext)obj;
            try
            {
                var mailSet = svc.GetMailList(context.ETypeCode);
                if (mailSet.Length > 0)
                {
                    mCfg.Revcivers = mailSet;
                    mCfg.MContent = context.Content;
                    mailSvc.MSNDAsync(mCfg);
                }
            }
            catch (Exception ex)
            {
                EventLog.WriteEntry(log_source, ex.ToString(), EventLogEntryType.Error);
            }
        }
#endif

    }

#if EMAIL
    public class SendMainContext
    {
        public string ETypeCode { get; set; }

        public string Content { get; set; }
    }
#endif
}